#include "udp.h"
#include "protocal_define.h"
#include "respond_struct_define.h"
#include <arpa/inet.h>
#include <ifaddrs.h>
#include <netdb.h>
#include <plog/Log.h>
#include <sys/socket.h>
#include <thread>

/*
function: 创建udp通信
param: port udp通信端口号
*/
Udp::Udp(int port, const char *serverip, std::function<void(uint8_t *, int)> callback)
    : clientport(port), _on_recv(callback) {
    bzero(&m_sender_addr, sizeof(m_sender_addr));

    m_sender_addr.sin_family = AF_INET;
    m_sender_addr.sin_addr.s_addr = inet_addr(serverip); // 这个ip不能写死
    m_sender_addr.sin_port = htons(6002);

    /* 获取本机的ip地址 */
    struct ifaddrs *ifAddrStruct = NULL;
    void *tmpAddrPtr = NULL;
    getifaddrs(&ifAddrStruct);

    while (ifAddrStruct != NULL) {
        if (ifAddrStruct->ifa_addr->sa_family == AF_INET) // check it is IP4
        {
            tmpAddrPtr = &((struct sockaddr_in *)ifAddrStruct->ifa_addr)->sin_addr;
            if (inet_ntop(AF_INET, tmpAddrPtr, localIP, INET_ADDRSTRLEN)) {
                if (strcmp("127.0.0.1", localIP)) {
                    break;
                }
            }
        } else if (ifAddrStruct->ifa_addr->sa_family == AF_INET6) {
            // IPV6 用不到
        }
        ifAddrStruct = ifAddrStruct->ifa_next;
    }
    PLOG_DEBUG << "Local IP addr: " << localIP << ":" << clientport;
}

/*
function: 析构函数，删除已经申请的内存
*/
Udp::~Udp(void) {}

/*
function: 开始通信
return: 0 正常返回 -1 发生错误
*/
int Udp::StartCommunication(void) {
    sockfd = socket(AF_INET, SOCK_DGRAM, 0);
    if (sockfd == -1) {
        PLOG_ERROR << "get sockfd failed.";
        return -1;
    }
    sockaddr_in serveraddr;
    socklen_t sender_addr_len = sizeof(struct sockaddr_in);

    bzero(&serveraddr, sizeof(serveraddr));
    serveraddr.sin_family = AF_INET;
    serveraddr.sin_port = htons(clientport);         // 指定端口
    serveraddr.sin_addr.s_addr = inet_addr(localIP); // 填写本机ip地址
    // 绑定自己的端口号和IP
    if (bind(sockfd, (sockaddr *)&serveraddr, sizeof(serveraddr)) == -1) {
        PLOG_ERROR << "bind sockfd with server addr failed.";
        return -1;
    }

    uint8_t recvbuffer[MAX_BUFFER_SIZE];

    while (true) {
        bzero(recvbuffer, sizeof(recvbuffer));
        int recvlen = recvfrom(sockfd, recvbuffer, sizeof(recvbuffer), 0,
                               (struct sockaddr *)(&m_sender_addr), &sender_addr_len);
        if (-1 == recvlen) {
            PLOG_ERROR << "recvfrom failed.";
            return -1;
        }
        _on_recv(recvbuffer, recvlen);
    }

    close(sockfd);
    return 0;
}

/*
function: 发送数据到服务端
param:  buffer 数据指针
        len 数据长度
        addr 发送到指定的端口和地址
return: 实际发送的数据长度
*/
int Udp::SendMsg(const uint8_t *buffer, int len) {
    int acturallength =
        sendto(sockfd, buffer, len, 0, (struct sockaddr *)(&m_sender_addr), sizeof(m_sender_addr));

    // for (int i = 0; i < acturallength; i++) {
    //     printf("/0x%02x/ ", buffer[i]);
    // }
    // printf("\r\n");

    return acturallength;
}
